package com.docker.core.third.websocket;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.docker.core.mvc.Remark;
import com.docker.core.mvc.controller.BaseAPIController;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Record;
import kit.docker.datetime.DateKit;

import javax.websocket.*;

/**
 * @Author ldl
 * @Create 2020/08/14 014 17:32
 */
@Remark("websocket基础控制层")
public abstract class BaseWebsocketController extends BaseAPIController {

    private String connect_key;
    private Session session;

    /**
     * @Param: [null]
     * @return: TODO
     * @Author: zhl
     * @Create: 2021/1/22 14:46
     **/
    @Remark("打开连接之前")
    protected abstract void onOpenBefore(Session session, String connectKey);

    /**
     * @Param: [session 连接session]
     * @return: void[发送信息]
     * @Author: ldl
     * @Create: 2020/08/16 016 14:12
     */
    @Remark("连接建立成功调用的方法")
    @OnOpen
    public void onOpen(Session session) {
        onOpenBefore(session, connect_key);
        this.connect_key = session.getRequestParameterMap().get("connect_key").get(0);
        this.session = session;

        //添加连接池
        WebsocketPool.addSocketPool(this.connect_key, new WebsocketPool(this.connect_key, session, DateKit.getNowDateTime()));

        //推送消息
//        sendMsg(session, WebsocketCMD.ON_OPEN, null);
//        logInfo("新增一个websocket连接！连接键" + this.connect_key + "，当前连接数为" + WebsocketPool.getPoolMap().size());
        onOpenAfter(session, connect_key);
    }

    /**
     * @Param: [null]
     * @return: TODO
     * @Author: zhl
     * @Create: 2021/1/22 9:56
     **/
    @Remark("给初始化的连接")
    protected abstract void onOpenAfter(Session session, String connectKey);

    /**
     * @Param: [message 接收到的消息json, session 连接session]
     * @return: void[发送消息]
     * @Author: ldl
     * @Create: 2020/08/16 016 15:15
     */
    @Remark("收到客户端消息后调用的方法")
    @OnMessage
    public void onMessage(String message, Session session) {
        WebsocketPool socketPool = WebsocketPool.getSocketPool(session);
        if (socketPool == null) {
            logInfo("应用没有连接，接收到的信息为：\n" + message);
            return;
        }

        //更新连接池信息
        socketPool.setConn_lastime(DateKit.getNowDateTime());
        WebsocketPool.addSocketPool(socketPool.getConnect_key(), socketPool);

        JSONObject msgJson;
        try {
            msgJson = JSONObject.parseObject(message);
        } catch (Exception e) {
            sendMsg(socketPool.getConnect_key(), WebsocketCMD.ON_ERROR, new Record().set("data", "消息格式错误[NOT JSON]"));
            return;
        }
        String cmd1 = msgJson.getString("cmd");
        String cmd2 = msgJson.getJSONObject("data").getString("cmd");
        if (StrKit.isBlank(cmd2) || !WebsocketCMD.SECOND_CMDS.contains(cmd2) || StringUtils.isEmpty(cmd1) || !WebsocketCMD.CMDS.contains(cmd1)) {
            sendMsg(socketPool.getConnect_key(), WebsocketCMD.ON_ERROR, new Record().set("data", "命令码未注册"));
            return;
        }

        //校验websocket的 session_token 是否过期

        onMessage(socketPool, msgJson);
    }

    //提供给子类实现的方法,处理接收到的消息
    protected abstract void onMessage(WebsocketPool socketPool, JSONObject msgJson);

    /**
     * @Param: [null]
     * @return: TODO
     * @Author: zhl
     * @Create: 2021/1/22 10:41
     **/
    @Remark("关闭之前的处理")
    protected abstract void onCloseBefore(Session session, String connectKey);

    /**
     * @Param: []
     * @return: void[发送消息]
     * @Author: ldl
     * @Create: 2020/08/16 016 15:18
     */
    @Remark("连接关闭调用的方法")
    @OnClose
    public void onClose() {
        onCloseBefore(session, connect_key);
        WebsocketKit.closeSocket(this.session);
        logInfo("连接键" + this.connect_key + "连接关闭！");
        onCloseAfter(session, connect_key);
    }

    /**
     * @Param: [null]
     * @return: TODO
     * @Author: zhl
     * @Create: 2021/1/22 10:41
     **/
    @Remark("关闭之后的处理")
    protected abstract void onCloseAfter(Session session, String connectKey);

    /**
     * @Param: [null]
     * @return: TODO
     * @Author: zhl
     * @Create: 2021/1/22 10:40
     **/
    @Remark("错误之前的处理")
    protected abstract void onErrorBefore(Session session, String connectKey);

    /**
     * @Param: [session 连接session, error 错误信息对象]
     * @return: void[发送消息]
     * @Author: ldl
     * @Create: 2020/08/16 016 15:18
     */
    @Remark("发生错误时调用")
    @OnError
    public void onError(Session session, Throwable error) {
        onErrorBefore(session, connect_key);
//        sendMsg(session, WebsocketCMD.ON_ERROR, new Record().set("message", error.getMessage()));
//        WebsocketKit.closeSocket(session);//发送错误关闭连接
        logInfo("websocket连接错误，连接键" + this.connect_key, error);
        onErrorAfter(session, connect_key);
    }

    /**
     * @Param: [null]
     * @return: TODO
     * @Author: zhl
     * @Create: 2021/1/22 10:40
     **/
    @Remark("错误之后的处理")
    protected abstract void onErrorAfter(Session session, String connectKey);

}
